

package localSearch;


import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.LinkedHashMap;
import java.util.Set;
import java.util.TreeMap;
import java.util.HashSet;
import java.util.Arrays;
import operations.AssignConstant;
import operations.CreateObject;
import operations.InvokeMethod;
import operations.CreateArray;
import operations.Operation;
import operations.ValuesGenerator;
import readWriteFieldsRelations.*;
import localSearch.LocalSearchPopulation;
import util.GAConfig;
import model.Filter;
import util.GAOperationsConfig;
import util.Log;
import util.DebugConfig;
import util.Randomness;
import model.CUT;
import model.MethodDeclared;
import model.StatementKind;
import model.TestClusterBuilder;
import instrumentation.Condition;
import instrumentation.ConditionSwitch;
import instrumentation.CoverageBranchTarget;
import instrumentation.Data;
import instrumentation.TrackerCoverage;
import ga.Individual;
import ga.GAInfo;
import executor.ReflectionExecutor;
public class HillClimbingMDA extends LocalSearchPopulation{

	private  TrackerCoverage tracker;
	private  long startTime;
	private  static long elapsed;
	private static long TestTimeout;
   private Map<Class<?>,  List<StatementKind>> statementDependences;

	@Override	
	public Individual execute()throws  IOException, ClassNotFoundException{
		System.out.println("	HillClimbing - MDA	");
		startTime=gaInfo.getStartTime();
		TestTimeout=gaInfo.getTestTimeOut();
		elapsed = (Calendar.getInstance().getTimeInMillis() - startTime);
		tracker = TrackerCoverage.getTracker();
		//Test Recommended Methods
//this.test();
		////////////////////////
		int trgtBranch=getTargetToCover(tracker);
		if(trgtBranch==-1) return null;
		Individual chrom =tracker.branchNotCoveredByIndividual.get(trgtBranch);
	   System.out.println("Branch# :" + trgtBranch );//+ " Original chrom: "+chrom.toString() );
	   if(chrom==null) return null;
	   statementDependences =getRecommendMethods(trgtBranch);
	   if(statementDependences==null) return null;
	LocalSearch HillClimbing = GAOperationsConfig.getLocalSearch();
	HillClimbing.displayConditionAndRecommendMethods(statementDependences, this.getCondition(trgtBranch), trgtBranch);
	 
	   if(statementDependences.size()==0)
		   return null;
			Individual result = hillClimb(chrom,trgtBranch);
			System.out.println("	HillClimbing - MDA end	");

			if(result!=null)
				return result;

		return null;
	}
	public void test(){
		List<Integer> branchs = new ArrayList<Integer>( gaInfo.getMapBranchCondition().keySet());  
		LocalSearch HillClimbing = GAOperationsConfig.getLocalSearch();
		for(int b=321;b<322;b+=2){
			int br=b;//branchs.get(b);
			Map<Class<?>,  List<StatementKind>>  statementDependences =this.getRecommendMethods(br);
			HillClimbing.displayConditionAndRecommendMethods(statementDependences, this.getCondition(br), br);
	}
		System.exit(0);
	}
	public Map<Class<?>,  List<StatementKind>>  getRecommendMethods(int trgtBranch){ 
	//	trgtBranch=71;
		Map<Class<?>,  List<StatementKind>> statementDependences =new LinkedHashMap<Class<?>, List<StatementKind>>();
		TestClusterBuilder TestCluster=this.gaInfo.getTestCluster();
		Condition c=this.getCondition(trgtBranch);
		Class<?> clazzMethodTarget=TestCluster.getClassToTest().get(c.getCName());
		if(clazzMethodTarget==null) return null;
		Data v1=null;
		v1= getDataCondition(trgtBranch,1);
		if(v1.isField()){
			 Map<Class<?>, Map<String, List<StatementKind>>> statementWriteFiled =gaInfo.getMethodRelations().getRelations().getStatementWriteFiled();
			 for(Class<?> clazz:statementWriteFiled.keySet()){
				 Map<String, List<StatementKind>> sWriteFields = statementWriteFiled.get(clazz);
				 if(sWriteFields.containsKey(v1.getFieldName()))
					 statementDependences.put(clazz, sWriteFields.get(v1.getFieldName()));				 
			 }
		}
		else{	// target is either param or N/A
			if(!c.getIsPrivate()){
				 Map<Class<?>, Map<StatementKind, List<StatementKind>>> statementDependence =gaInfo.getMethodRelations().getRelations().getStatementDependences();
				 for(Class<?> clazz:statementDependence.keySet()){
					 Map<StatementKind, List<StatementKind>> sWriteMethods= statementDependence.get(clazz);
					 for(StatementKind st:sWriteMethods.keySet()){
	//					 System.err.println("getRecommendMethods  st.toString() " + st.toString() + " c.getMName() "+ c.getMName()) ;
						 if(st.toString().equals(c.getMName())&& ((MethodDeclared) st).getMethod().getDeclaringClass().toString().contains(c.getCName())){
							List<StatementKind> list=statementDependences.get(c.getMName());
							if(list==null)
								list=new LinkedList<StatementKind>();
							list.addAll( sWriteMethods.get(st));
							HashSet<StatementKind> hashSet = new HashSet<StatementKind>(list);
							list=new LinkedList<StatementKind>(hashSet); 
							 	statementDependences.put(clazz, list);
						 }
					 }
				 }
			}
			else{
				//private 
				 Map<Class<?>, Map<String, List<StatementKind>>> statementPrivateCall =gaInfo.getMethodRelations().getRelations().getPrivateDependences();
				 for(Class<?> clazz:statementPrivateCall.keySet()){
					 Map<String, List<StatementKind>> sCallPrivate = statementPrivateCall.get(clazz);
					 for(String st:sCallPrivate.keySet())
						 if(st.toString().equals(c.getMName()))
							 	statementDependences.put(clazz, sCallPrivate.get(st));
				 }
				 //Add all methods that write in the public methods which call the private methods conatins the Target Branch
				 Map<Class<?>, Map<StatementKind, List<StatementKind>>> methodsDependence =gaInfo.getMethodRelations().getRelations().getStatementDependences();
				 for(Class<?> clazz:statementDependences.keySet()){
					  List<StatementKind> sWriteMethods= statementDependences.get(clazz);
	//				  System.out.println(sWriteMethods);

					  Map<StatementKind, List<StatementKind>> sWriteMethodsCallPrivate= methodsDependence.get(clazz);
					 for(StatementKind st:sWriteMethodsCallPrivate.keySet()){
//						 System.out.println(st.toString());
						 if(sWriteMethods.contains(st)){
							 List<StatementKind> wMethodsList=sWriteMethodsCallPrivate.get(st);
							 for(StatementKind st_:wMethodsList)
								 if(!sWriteMethods.contains(st_))
										 sWriteMethods.add(st_);
						 }
					 }

				 }

				
			}
		}
		if(!c.getIsPrivate()){
			CUT cut=TestCluster.getCluster().get(clazzMethodTarget.getName());

			if(c.getMName().contains("<init>")||statementDependences.get(clazzMethodTarget)==null){
				StatementKind[]  st=cut.getConstructors();
				List<StatementKind> list=new LinkedList<StatementKind>();
				if(list==null)
					list=new LinkedList<StatementKind>();
			
				list.addAll(Arrays.asList(st));

				statementDependences.put(clazzMethodTarget, list);
			
				
			}
				
			StatementKind[]  st=cut.getMethods();
			for(StatementKind s:st){
				if(s.toString().equals(c.getMName())){
					List<StatementKind> list=new LinkedList<StatementKind>(statementDependences.get(clazzMethodTarget));
					if(list==null)
						list=new LinkedList<StatementKind>();
					if(!list.contains(s))
						list.add(s);
					statementDependences.put(clazzMethodTarget, list);
					break;
				}
			}
		}
		if(statementDependences.size()==0){
			if(DebugConfig.HCPure){
				System.err.println("HCMDA.getRecommendMethods: There are no recommeneded statements for Br: "+ trgtBranch);
				Log.log("HCMDA.getRecommendMethods: There are no recommeneded statements for Br: "+ trgtBranch);
			}
				
		}
		
		return statementDependences;
	}
	
	private  Data getDataCondition(int trgtBR,int value){
		Map<Integer, Condition> mapBranchCondition=gaInfo.getMapBranchCondition();
	       TreeMap<Integer,Condition> sorted_map = new TreeMap<Integer,Condition>(mapBranchCondition);
	       if(sorted_map.containsKey(trgtBR)){
	   			Condition c= sorted_map.get(trgtBR);
					if(value==1){
						if(c.getV1() instanceof Data)
							return (Data) c.getV1();
					}
					if(value==2){
						if(c.getV2() instanceof Data)
							return (Data) c.getV2();
					}
				}

		
		return null;
	}

	public int getTargetToCover(TrackerCoverage tracker)throws  IOException, ClassNotFoundException{
		List<Integer> branchs = new ArrayList<Integer>( gaInfo.getMapBranchCondition().keySet());  
		
		int trgtBR=-1;
		Map<Integer,CoverageBranchTarget> trackers=tracker.getTrackers();
		List<Integer> keys = new ArrayList<Integer>(trackers.keySet());
			CoverageBranchTarget condTrgt=null;
		int times=0;
		while(trgtBR==-1){
			times++;
			for ( int indx = 0; indx < keys.size(); indx++) {
				int considerBr=	keys.get(indx);
				if(tracker.branchNotCoveredByIndividual.containsKey(considerBr)){ 
					condTrgt = (CoverageBranchTarget) trackers.get(considerBr);
					Condition c =this.getCondition(considerBr);
					if(c==null) continue;
					if(c.getIsCallMethod()&&times!=2) continue;
					if(condTrgt==null) continue;

					if( condTrgt.getAttempt()!=gaInfo.getAttempt()){
						trgtBR=considerBr;

						break;
					}

			}
			}//for indx

			if(tracker.branchNotCoveredByIndividual.size()==0)
				return -1;
			if(trgtBR==-1)
				gaInfo.setAttempt(gaInfo.getAttempt()+1);
			else{
				condTrgt = (CoverageBranchTarget) trackers.get(trgtBR);
				condTrgt.setAttempt(gaInfo.getAttempt());
			}
			if(!branchs.contains(trgtBR))
				return -1;

		}
			return trgtBR;
	
	}
	private Condition getCondition(int trgtBR){
		Map<Integer, Condition> mapBranchCondition=gaInfo.getMapBranchCondition();
	       TreeMap<Integer,Condition> sorted_map = new TreeMap<Integer,Condition>(mapBranchCondition);
	       if(sorted_map.containsKey(trgtBR)){
	   			Condition c= sorted_map.get(trgtBR);
	   			return c;
	       }
		return null;
	}
	private static final int ITERATIONS = 100;
	/** Number of attempts when a method is selected */
	private final int TTL_FIRST = 10;
	/** Number of attempts for operations able to reduce the branch distance */
//	private final int TTL_IMPROVEMENT  = 20;
	public Individual hillClimb (Individual originalIndividual,int trgtBR){
//		if(trgtBR==25)
//			Log.log("covCondOrig "  );
		int ttl = 0;//how many times that a position/ method can be targeted again
		Map<Integer,CoverageBranchTarget> trackers=tracker.getTrackers();
		CoverageBranchTarget covCondOrig = (CoverageBranchTarget) trackers.get(trgtBR);
		float origBranchDistFitness=covCondOrig.getQuality();	
		if(covCondOrig==null) return null;

		if(DebugConfig.HCPure)
				Log.log("covCondOrig " + covCondOrig.getQuality() );
		Individual individualMuted=null;
		for (int i = 0; i < ITERATIONS && elapsed < TestTimeout; i++) {
		if(--ttl < 0) {
			individualMuted=originalIndividual.clone();	
			ttl = TTL_FIRST;
		}
		if(i%100==0)
			System.out.println("BR: "+ trgtBR + " ITERATIONS " +i + " of "+ ITERATIONS);

		// the mutate operations must change the size of the individual, except in the modify operations that returns the same size of the indiviuals with the original
			boolean canContinue = true;
//			System.out.println(trgtBR + " originalIndividual " + originalIndividual.getSize() );
			if(DebugConfig.HCPure)
				Log.log("individualMuted-1 " + individualMuted.getSize() );
	
			canContinue=mutate(individualMuted,trgtBR);
		
		    if(DebugConfig.HCPure)
				Log.log("individualMuted-2 " + individualMuted.getSize() );

	//		System.out.println( trgtBR+ " individualMuted " +individualMuted.getSize());



			tracker.reset();
			ReflectionExecutor.execute( gaInfo,individualMuted);
//			System.out.println(trgtBR +" after extecution " +individualMuted.getSize());

			float[] fitness= tracker.calculateHCFitness(individualMuted,trgtBR);
		
			if(!stillFeasible(trgtBR)) continue;

			CoverageBranchTarget mutetedCondOrig = (CoverageBranchTarget) trackers.get(trgtBR);

			if(DebugConfig.HCPure)
						Log.log("mutetedCondOrig " + mutetedCondOrig.getQuality() );
		
//			System.out.println("origBranchDistFitness " + origBranchDistFitness );
//			System.out.println("mutetedCondOrig " + mutetedCondOrig.getQuality() );
			
			if(mutetedCondOrig.getQuality() == 0) {
				System.err.println("Target " + mutetedCondOrig.toString() + " hit");
	//			Log.info("Target " + mutetedCondOrig.toString() + " hit");
						return individualMuted;
			}
			if(mutetedCondOrig.getQuality() == origBranchDistFitness&& individualMuted.getSize() < originalIndividual.getSize()) {
				originalIndividual=individualMuted.clone();
				originalIndividual.setBranchDistance(originalIndividual.getBranchDistance());
				originalIndividual.setFitness(mutetedCondOrig.getQuality());
			}
//			originalIndividual=individualMuted;
			if(mutetedCondOrig.getQuality()!=origBranchDistFitness){
					origBranchDistFitness=mutetedCondOrig.getQuality();
//					ttl = TTL_IMPROVEMENT;
					originalIndividual=individualMuted.clone();
					originalIndividual.setBranchDistance(individualMuted.getBranchDistance());
					originalIndividual.setFitness(individualMuted.getFitness());
				}
			 elapsed = (Calendar.getInstance().getTimeInMillis() - startTime);
		}
		return null;
	}
	private boolean stillFeasible(int BR){
		if(tracker.individualBestAcievedDistance.containsKey(BR))
			return true;
		
		return false;
	
	}

	/** probability to add an operation(s)  */
	private float probAdd = 0.5f;

	/** probability to remove  an operation(s) */
	private float probRemove = 0.2f;

	/**   probability to modify the parameters of  an operation(s)*/
	private float probModify = 0.3f;


	public boolean mutate(Individual individual,int trgtBR){
		List<Operation> ops = individual.getStatements();		
		final boolean isModifiable = ops.size() >= 0 ;// && this.isPredicateTypePrimitive(trgtBR);
		final boolean isRemovable = ops.size()>3;
	    if(DebugConfig.HCPure)
			Log.log("start mutate" + individual.getSize() );

		int choice;
		/** 0 => add; 1 => modify; 2 => remove */
		if(isModifiable && isRemovable) {
			float c = Randomness.random.nextFloat() * (probAdd + probModify + probRemove);
			if(c < probAdd) choice = 0;
			else if(c < probAdd + probModify) choice = 1;
			else choice = 2;
		} else if(isModifiable) {
			float c = Randomness.random.nextFloat()* (probAdd + probModify);
			if(c < probAdd) choice = 0;
			else choice = 1;
		} else if(isRemovable) {
			float c = Randomness.random.nextFloat()* (probAdd + probRemove);
			if(c < probAdd) choice = 0;
			else choice = 2;
		} else choice = 0;
		int pos = Randomness.random.nextInt(ops.size());
		
		choice=0;
		if(choice==0){
			if(DebugConfig.HCPure)
				Log.log("Add Method-1: " + individual.getSize());
			
			addOperationsRandomly(ops,trgtBR);
	
			if(ValuesGenerator.getBoolean(0.8f)&& GAConfig.Seeding)
				modifyOperations(individual,trgtBR);
			if(DebugConfig.HCPure)
				Log.log("Add Method-2: " + individual.getSize());

			return true;
		}else if(choice==1){
			if(DebugConfig.HCPure)
				Log.log("method modify -1: " + individual.getSize());
			modifyOperations( individual,  trgtBR);
//			} else if (ops.get(pos) instanceof AssignConstant) {
//				Operation mutateOp = mutantAssignConstant(
//						(AssignConstant) ops.get(pos), individual);
//				ops.set(pos, mutateOp);
//			}
			if(DebugConfig.HCPure)
				Log.log("method modify -2: " + individual.getSize());

			return false;
		}else if(choice==2){
			if(DebugConfig.HCPure)
				Log.log("remove operation-1: "+ individual.getSize());
			removeOperations(individual,trgtBR);
			if(DebugConfig.HCPure)
				Log.log("remove operation-1: "+ individual.getSize());
			return true;
		}else{
			System.err.println("HillCimbing.mutate: undefined operation");
		}
	    if(DebugConfig.HCPure)
			Log.log("end mutate" + individual.getSize() );

		return true;
	}

	private void addOperationsRandomly(List<Operation> ops, int trgtBR) {
			int numberMethodsAdded=ValuesGenerator.getRandomIntBetween(1,10 + gaInfo.getAttempt());
			int randPos=ValuesGenerator.getRandomIntBetween(0,ops.size()-1);
			List<Operation> rep = new LinkedList<Operation>();
			rep.addAll(ops.subList(0, randPos));

			List<Operation> newOps=	Operation.recommendedGenerate(gaInfo.getTestCluster(),numberMethodsAdded,statementDependences);
			rep.addAll(newOps.subList(0, newOps.size()));
			
			rep.addAll(ops.subList(randPos, ops.size()));
			ops.clear();
			ops.addAll(rep.subList(0, rep.size()));
		}
	private void modifyOperations(Individual individual, int trgtBR) {
//		if(trgtBR==15)
//			System.out.print("");
		TestClusterBuilder TestCluster=this.gaInfo.getTestCluster();
		Map<String, CUT>  cluster= TestCluster.getCluster();
	
		 Map<Class<?>,  List<StatementKind>> recStatements=this.statementDependences;	
			List<Class<?>> recClassToTest= new ArrayList<Class<?>>(recStatements.keySet());
			Class<?> clz=recClassToTest.get(Randomness.nextRandomInt(recClassToTest.size()));
			List<StatementKind> statements=recStatements.get(clz);

		// Get the recommended values if exist and its type and the index of the parameter 
		 Condition condition =this.getCondition(trgtBR);
			String pValue_v2=null;
			String extraInfo=null;
			Object pType=null;
			Object callee=null;
			int paramIndx=-1;
			if(condition.getV1() instanceof Data){
				Data v1=(Data) condition.getV1();
				if(v1.isField()){
					pType=v1.getType();
					callee=condition.getCallee1();
				}
				else if(v1.getIndxParam()!=-1){
					pType=v1.getType();
					paramIndx=v1.getIndxParam();
				}
			}

			if(condition.getV2() instanceof instrumentation.Constant){
				pValue_v2=condition.getV2().toString();
			}
			else 
				if(condition.getV2() instanceof instrumentation.ConstantString)
					pValue_v2=condition.getV2().toString();
				
			if(condition instanceof ConditionSwitch )
				pValue_v2=""+((ConditionSwitch) condition).getCases().get(trgtBR);
			
			
			
			Class<?> pValueTyp=null;
			if(pType!=null)
				if(pType.toString().contains("[")){
					extraInfo=condition.getExtraInfo();
					if(extraInfo!=null)
						pType=pType.toString().substring(0, pType.toString().indexOf('['));
					
				}
			if(condition.getIsCallMethod())
				if(condition.getExtraInfo()!=null)
					pType=condition.getExtraInfo();

			if(pType==null)
				pType=condition.getType().toString();

			
			if(pType!=null)
					pValueTyp=Filter.getPrimitiveTypeOrString(pType.toString());
				
			if(pValueTyp==null&&pType!=null){
				CUT cut =cluster.get(pType.toString()) ;
				if(cut!=null)
					pValueTyp=cut.getClazz();
			}
			if(pValueTyp!=null)
			 if(extraInfo!=null&&!extraInfo.contains("Length")){
				if(pValueTyp.equals(String.class)||pValueTyp.equals(Character.class)||pValueTyp.equals(char.class))
					if(Filter.isNumeric(pValue_v2))
						pValue_v2= ""+(char) Integer.parseInt(pValue_v2);
			}else{
				if(pValueTyp.equals(String.class)||pValueTyp.equals(Character.class)||pValueTyp.equals(char.class))
					if(Filter.isNumeric(pValue_v2))
						pValue_v2= ""+(char) Integer.parseInt(pValue_v2);			
			}
					
					Object pValue=ValuesGenerator.mapValueToObject(pValueTyp, pValue_v2);
			//Modify initial constructors
			List<Operation> initialConstr = individual.getInitialConstructors();
			for(Operation op : initialConstr) {
				if (op instanceof CreateObject){
					if(statements.contains(((CreateObject)op).getConstructor()))
						op = mutantConstructoParams(pValueTyp,pValue,paramIndx,(CreateObject) op, individual);				
				}

			}
			if(!GAConfig.Seeding)
				pValue=null;
			
			//get operations of the inidividual;
			List<Operation> ops = individual.getStatements();
			for(Operation op : ops) {	
				if (op instanceof CreateObject){
					for(int i=0;i<statements.size();i++)
						if(statements.get(i).toString().equals(((CreateObject)op).getConstructor()))
							op = mutantConstructoParams(pValueTyp,pValue,paramIndx,(CreateObject) op, individual);
				
		}
			else
				if(op instanceof InvokeMethod){
					for(int i=0;i<statements.size();i++)
						if(statements.get(i).toString().equals(((InvokeMethod)op).getMethod().toString()))
							op=this.mutantMethodParams(pValueTyp,pValue,paramIndx,extraInfo, (InvokeMethod) op, individual) ;
				}
				else
					if(op instanceof CreateArray){						
						if(((CreateArray)op).getElementType().equals(pValueTyp))
							op=this.mutantArrayElements(pValueTyp,pValue,paramIndx,extraInfo, (CreateArray) op, individual) ;
					}
			}//for 
	}
	private void removeOperations(Individual individual, int trgtBR) {
		 Map<Class<?>,  List<StatementKind>> recStatements=this.statementDependences;		 	
			List<Operation> ops = individual.getStatements();
			List<Class<?>> recClassToTest= new ArrayList<Class<?>>(recStatements.keySet());
			Class<?> clz=recClassToTest.get(Randomness.nextRandomInt(recClassToTest.size()));
			List<StatementKind> statements=recStatements.get(clz);
			if(statements.size()==0){
				System.err.println("Hillclimbing.removeOperations: There are no method to recommend!");
				return;
			}
			// choose a writing method to delete!
			int randMethod = Randomness.nextRandomInt(statements.size());
			StatementKind st=statements.get(randMethod);
		
			List<StatementKind> methodList= new LinkedList<StatementKind>();
			methodList.addAll(statements);
			methodList.removeAll(Collections.singleton(st));

			List<Operation> newOps = new LinkedList<Operation>();
	
			//remove operations from the individual
			int num = Randomness.nextRandomInt(10);
			for(Operation op : ops) {
					if (op instanceof CreateObject){
						 if(methodList.contains(((CreateObject)op).getConstructor()))
							 	newOps.add(op);
					}
					else if(op instanceof InvokeMethod){
						 if(methodList.contains(((InvokeMethod)op).getMethod()))
							 	newOps.add(op);
						 }
				}
			if(newOps.size()!=0){
				ops.clear();
				ops.addAll(newOps);
			}

	}
	private Operation mutantArrayElements(Class<?>tValue, Object recValue,int indx,String extraInfo,CreateArray op,Individual individual)  {
		TestClusterBuilder TestCluster=this.gaInfo.getTestCluster();
		 CreateArray array=((CreateArray)op);
		   if(extraInfo!=null&&extraInfo.equals("Length")&& GAConfig.Seeding)
			   array.setLength(Integer.parseInt(recValue.toString()));
		   
		   List<Object> inputList=array.getInputVariables();

		   if(Filter.isPrimitiveOrStringType(array.getElementType())&& GAConfig.Seeding){
			   if(extraInfo!=null&&extraInfo.contains("Index:")){
				   String indexArray=extraInfo.substring(extraInfo.lastIndexOf(':')+1);
				   int index=Integer.parseInt(indexArray);
				   if(inputList.size()>index&&ValuesGenerator.getBoolean(.9f)){
					   inputList.set(index, recValue);
					   return op;
				   }
			   }
		   }
		    for (int i = 0; i < array.getLength(); i++)
		    	if(Filter.isPrimitiveOrStringType(array.getElementType())){
		    		if(i<inputList.size())
		    				inputList.set(i, ValuesGenerator.modifyPrimitiveValue(array.getElementType(),inputList.get(i)));
		    		else
		    			inputList.add(ValuesGenerator.generatePrimitiveValue(array.getElementType()));
		    	}
		    	else
		    		inputList.set(i, Operation.generateReference(array.getElementType(),TestCluster));

		return op;		
	}

	private Operation mutantMethodParams(Class<?>tValue, Object recValue,int indx,String extraInfo,InvokeMethod op,Individual individual)  {
//		System.err.println("mutantMethodParams-enter : "+op.toString());
	
		List<Class<?>> newReplacementObejctParams=new LinkedList<Class<?>>(op.getReplacementObjectParam());
		TestClusterBuilder TestCluster=this.gaInfo.getTestCluster();

		StatementKind m = op.getMethod();
		List<Class<?>> paramsTpe = m.getInputTypes();
		List<Object> oldValues=new LinkedList<Object>(op.getValues());
		List<Object> newValues=new LinkedList<Object>();
		int indexReplacementObejctParams=0;
		//Change return reference
			String _return = (((MethodDeclared) m).isVoid()) ? null : Operation.getReference(((MethodDeclared) m).getMethod().getReturnType().getName(), TestCluster.getRefFactory());
			if(_return==null){
				Class<?> rType=((MethodDeclared) m).getMethod().getReturnType();
				if(!rType.getName().contains("java"))
				if(!rType.getName().startsWith("sun"))
				if(!rType.getName().contains("$")) 
					if(!((MethodDeclared) m).isVoid()&&!Filter.isPrimitiveOrStringType(rType)){
						Operation.replacementObjectParam.clear();
							Object clz2= Operation.generateReference(rType, TestCluster);
							if(clz2!=null)
								_return=clz2.toString();	
					}
			}

			op.setReturn(_return);
		//change parameters
		boolean commitedChange=false;
		for(int i = 0; i < paramsTpe.size(); i++) {
				Operation.replacementObjectParam.clear();
				if (Filter.isPrimitiveOrStringType(paramsTpe.get(i))){
					Object randValue=ValuesGenerator.generatePrimitiveValue(paramsTpe.get(i));
					oldValues.set(i,ValuesGenerator.modifyRecommendedValue(oldValues.get(i),randValue,paramsTpe.get(i)));
					if(tValue==null) continue;
					if(ValuesGenerator.getBoolean(.9f)&& GAConfig.Seeding){
						if (Filter.isPrimitiveOrStringType(tValue)&&tValue.equals(paramsTpe.get(i)))
							oldValues.set(i,ValuesGenerator.modifyRecommendedValue(oldValues.get(i),recValue,tValue));
					}
				}
					else{
						oldValues.set(i, Operation.generateReference(paramsTpe.get(i), TestCluster));
						if(Operation.replacementObjectParam.size()!=0&&newReplacementObejctParams.size()>indexReplacementObejctParams)
							newReplacementObejctParams.set(indexReplacementObejctParams, Operation.replacementObjectParam.get(0));
						else{
								if(Operation.replacementObjectParam.size()>0){
									newReplacementObejctParams.add(Operation.replacementObjectParam.get(0));
									indexReplacementObejctParams++;
								}
						}
					}
			}
		newValues.addAll(oldValues);
		op.setValues(newValues,newReplacementObejctParams);
//		System.err.println("mutantMethodParams-exit : "+op.toString());
		return op;
	}
	private Operation mutantConstructoParams(Class<?>tValue, Object recValue,int indx,CreateObject op,Individual individual)  {
		
		TestClusterBuilder TestCluster=this.gaInfo.getTestCluster();
		StatementKind cons = op.getConstructor();
		List<Class<?>> paramsTpe = cons.getInputTypes();
		List<Object> oldValues=new LinkedList<Object>(op.getValues());

		for(int i = 0; i < paramsTpe.size(); i++) {
			if (Filter.isPrimitiveOrStringType(paramsTpe.get(i))){
				Object randValue=ValuesGenerator.generatePrimitiveValue(paramsTpe.get(i));
				oldValues.set(i,ValuesGenerator.modifyRecommendedValue(oldValues.get(i),randValue,paramsTpe.get(i)));
				if(tValue==null) continue;
				if(ValuesGenerator.getBoolean(.9f) && GAConfig.Seeding){
					if (Filter.isPrimitiveOrStringType(tValue)&&tValue.equals(paramsTpe.get(i)))
						oldValues.set(i,ValuesGenerator.modifyRecommendedValue(oldValues.get(i),recValue,tValue));
				}
			}
		}
		List<Object> newValues=new LinkedList<Object>(oldValues);
		op.setValues(newValues);
		return op;
	}
	private Operation mutantAssignConstant(AssignConstant op,Individual individual)  {
		TestClusterBuilder TestCluster=this.gaInfo.getTestCluster();
		Map<String, CUT>  cluster= TestCluster.getCluster();
		String cName= ((AssignConstant) op).getDeclaringClass().getName();
		CUT cut =cluster.get(cName) ;
//		String ref_=op.getRefrence();
		op = AssignConstant.generate(cut,TestCluster);
		return op;
	}

	private static void simpleTestExecute(GAInfo     gaInfo,TestClusterBuilder TestCluster)throws ClassNotFoundException{
		  TrackerCoverage tracker=  TrackerCoverage.getTracker();
		
		  List<Operation> initialConstructors= Operation.generateInitialConstructors(TestCluster);

	      List<Operation> ops=new LinkedList<Operation>();
    	  ops.addAll(Operation.randomlyGenerate(TestCluster,GAConfig.TestCaseSize));
	      Individual individual=new Individual(initialConstructors,ops);

			System.out.println(individual.toString());
			
			ReflectionExecutor.execute(gaInfo,individual);
			tracker.calculateFitness(individual,gaInfo.getMapBranchCondition().keySet());

			System.out.println("------------------------");
			  System.out.println(tracker.toString());
				System.out.println(tracker.displayCondition());

	}

	public static void main(String[] args) throws ClassNotFoundException,IOException{
		String logFilePath = "/nfs/guille/u2/a/aburas/WorkSpace/MAMDA_V2.14/MA_MDA_5/temp/HCMDA.txt";
		Log.logConfig(logFilePath);
		new File(logFilePath).getAbsolutePath();
	
		for (int i = 0; i <= 0; i += 6) {
			GAInfo gaInfo = new GAInfo();
			Randomness.reset(10);
			long startTime = Calendar.getInstance().getTimeInMillis();
			gaInfo.setTestTimeOut(60 * 500);
			 gaInfo.setTestTimeOut( 60 * 1000*10); ;

			gaInfo.setStartTime(startTime);

			Set<Class<?>> allClasses = new LinkedHashSet<Class<?>>();
			// get class from file
			allClasses.addAll(TestClusterBuilder.readClassFromFile());

			TestClusterBuilder TestCluster = new TestClusterBuilder(allClasses);
			gaInfo.setTestCluster(TestCluster);
			 if(GAConfig.UseReadWrietRelation){
				 System.out.println( "Building up method dependence model for diversifying...");
				 Set<Class<?>> cluster = new LinkedHashSet<Class<?>>();
					for(String cName:TestCluster.getCluster().keySet()){
						Class<?> cls=TestCluster.getCluster().get(cName).getClazz();
						if(Filter.isPrimitiveOrStringType(cls))continue;
						if(cls.getName().contains("java")) continue;
						if(cls.getName().startsWith("sun")) continue;
						if(cls.getName().contains("$")) continue;
						if(!Filter.canUse(cls))continue;
						cluster.add(cls);
					}

					MethodDependences recommender = new MethodDependences(cluster);
					 recommender.buildDependence(TestCluster.getStatements());
					 System.out.println("Finishing method dependence model building");
					 gaInfo.setMethodRelations(recommender);
			 }
		
		    GAConfig.UseReadWrietRelation=true;

			LocalSearch HillClimbing = GAOperationsConfig.getLocalSearch();
			HillClimbing.setExtraInfo(gaInfo);
			gaInfo.setMapBranchCondition(HillClimbing.readFileWGZ(gaInfo.getTestCluster()));
			System.out.println("Hill Climbing ( MDA )");
			List<Integer> branchs = new ArrayList<Integer>( gaInfo.getMapBranchCondition().keySet());  
			List<TestClusterBuilder> TestClusterList= TestClusterBuilder.buildTestClusterList(allClasses);
			for(TestClusterBuilder tCluster:TestClusterList){

				for (int j = 0; j < 1; j++) {
					simpleTestExecute(gaInfo, tCluster);
				}
				}
			TrackerCoverage tracker = TrackerCoverage.getTracker();
			System.out.println("------------------------");
			System.out.println(tracker.displayCoveredBranchs(branchs));
			// System.out.println(tracker.displayCondition());

			int no = tracker.branchNotCoveredByIndividual.size();
//			 for (int k = 0; k <=no -1;k++){
			for (int k = 0;  elapsed < gaInfo.getTestTimeOut(); k++) {
				Individual improvedIndividual = HillClimbing.execute();
				
//				if(	tracker.branchNotCoveredByIndividual.size()==0)
//					break;
			}
			System.out.println("------------------------");
			System.out.println(tracker.displayCoveredBranchs(branchs));
			if(GAConfig.SaveData)
				Log.log(tracker.displayCoveredBranchs(branchs));

			 tracker.summarizeCoverage(branchs);
		}
			System.exit(0);

	}

}